﻿using Microsoft.Extensions.DependencyModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;

namespace Microsoft.Extensions.DependencyInjection
{
    public static class AutoFacHelper
    {
        static readonly List<CompilationLibrary> compilationLibraries;
        static AutoFacHelper()
        {
            compilationLibraries = DependencyContext.Default.CompileLibraries.Where(c => !c.Serviceable && c.Type != "package").ToList();
        }
        /// <summary>
        /// 枚举
        /// </summary>
        public enum RegType
        {
            /// <summary>
            /// 瞬态
            /// </summary>
            Transient = 0,
            /// <summary>
            /// 作用域
            /// </summary>
            Scoped,
            /// <summary>
            /// 单例
            /// </summary>
            Singleton
        }
        /// <summary>
        /// 接口注入
        /// </summary>
        /// <param name="services"></param>
        /// <param name="where"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static IServiceCollection AutoFacInterface(this IServiceCollection services, Func<CompilationLibrary, bool> where = null, RegType type = RegType.Scoped)
        {
            var libs = compilationLibraries;
            //排除系统和包文件
            if (where != null)
            {
                libs = libs.Where(where).ToList();
            }

            if (libs.Count == 0)
            {
                return services;
            }
            var list = new List<Assembly>();
            //将程序集加载,并存放进list
            libs.ForEach((x) => { list.Add(AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(x.Name))); });

            var interfaceList = new List<TypeInfo>();//接口
            var implementationTypeList = new List<TypeInfo>();//实现
            //将接口和普通类分开IsInterface和IsClass
            foreach (var assemb in list)
            {
                interfaceList = interfaceList.Union(assemb.DefinedTypes.Where(x => x.IsInterface).ToList()).ToList();
                implementationTypeList = implementationTypeList.Union(assemb.DefinedTypes.Where(x => x.IsClass).ToList()).ToList();
            }
            //注入开始
            foreach (var interfaceType in interfaceList)
            {
                //查找接口的第一个实现
                var implementationType = implementationTypeList.Where(x => x.ImplementedInterfaces.Any(c => c.FullName == interfaceType.FullName)).FirstOrDefault();
                if (implementationType == null)
                {
                    continue;
                }
                //注入
                switch (type)
                {
                    case RegType.Transient: services.AddTransient(interfaceType.AsType(), implementationType.AsType()); break;
                    case RegType.Scoped: services.AddScoped(interfaceType.AsType(), implementationType.AsType()); break;
                    case RegType.Singleton: services.AddSingleton(interfaceType.AsType(), implementationType.AsType()); break;
                    default: break;
                }
            }
            return services;
        }
        /// <summary>
        /// 类注入
        /// </summary>
        /// <param name="services"></param>
        /// <param name="where"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static IServiceCollection AutoFacClass(this IServiceCollection services, Func<CompilationLibrary, bool> where = null, RegType type = RegType.Scoped)
        {
            var libs = compilationLibraries;
            //排除系统和包文件
            if (where != null)
            {
                libs = libs.Where(where).ToList();
            }

            if (libs.Count == 0)
            {
                return services;
            }
            var list = new List<Assembly>();
            //将程序集加载,并存放进list
            libs.ForEach((x) => { list.Add(AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(x.Name))); });

            var implementationTypeList = new List<TypeInfo>();//实现
            //将接口和普通类分开IsInterface和IsClass
            foreach (var assemb in list)
            {
                implementationTypeList = assemb.DefinedTypes.Where(x => x.IsClass && x.ImplementedInterfaces.Count() == 0).ToList();
            }
            //注入开始
            foreach (var implementationType in implementationTypeList)
            {
                //注入
                switch (type)
                {
                    case RegType.Transient: services.AddTransient(implementationType.AsType()); break;
                    case RegType.Scoped: services.AddScoped(implementationType.AsType()); break;
                    case RegType.Singleton: services.AddSingleton(implementationType.AsType()); break;
                    default: break;
                }
            }
            return services;
        }
    }
}
